package fi.pyppe.android.gps.util;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.channels.FileLock;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;

import android.app.AlertDialog;
import android.content.DialogInterface;
import android.location.Location;
import android.os.Environment;
import android.util.Log;
import android.widget.EditText;

import fi.pyppe.android.gps.PyppeGPSActivity;
import fi.pyppe.android.gps.PyppeGPSConstants;

/**
 * KMLWriter.
 * 
 * @author Pyppe
 */
public class KMLWriter {
  private PyppeGPSActivity pyppeGPSActivity;
  private FileLock kmlLock;
  private boolean allowTagging = false;
  private Date startTime;
  private Date endTime;
  private static final String EXTRA_DATA = "<!--@ExtraData@-->";
  private static final String START_OF_KML = 
    "<?xml version=\"1.0\"?>" + System.getProperty("line.separator") +
    "<kml xmlns=\"http://www.opengis.net/kml/2.2\">" + System.getProperty("line.separator") +
      "<Document>" + System.getProperty("line.separator") +
        "<name>PyppeGPS</name>" +
        "<Style id=\"gpsLineStyle\">" +
          "<LineStyle>" +
            "<color>ff00ff66</color>" +
            "<width>3</width>" +
          "</LineStyle>" +
          "<PolyStyle>" +
            "<color>ff00ff66</color>"+
          "</PolyStyle>" +
        "</Style>" + System.getProperty("line.separator") +
        "<Placemark>" + 
          "<name>Track</name>" +
          "<styleUrl>#gpsLineStyle</styleUrl>" +
          EXTRA_DATA +
          "<LineString>" +
            "<extrude>1</extrude>" +
            "<tessellate>1</tessellate>" +
            "<altitudeMode>absolute</altitudeMode>" +
            "<coordinates>" + System.getProperty("line.separator"); // This must be the last node of LineString!
  private static final String END_OF_COORDINATES = 
            "</coordinates>" +
          "</LineString>" +
        "</Placemark>";
  private static final String END_OF_KML =
      "</Document>" +
    "</kml>";
  
  private String annotatedPlacemarks;

  public KMLWriter(PyppeGPSActivity activity) {
    pyppeGPSActivity = activity;
  }

  public void writeToFile(Location loc) {
    try {
      File outputFolder = new File(Environment.getExternalStorageDirectory(), PyppeGPSConstants.OUTPUT_FOLDER);
      if (!outputFolder.exists()) {
        outputFolder.mkdirs();
      }

      writeLocationToKmlFile(loc, outputFolder);
      allowTagging = true;
    } catch (Exception e) {
      Log.e("Main", "Could not write file " + e.getMessage());
      pyppeGPSActivity.setStatusText("Could not write to file: " + e.getMessage());
    }
  }
  
  

  public void writeLocationToKmlFile(Location loc, File gpxFolder) {
    try {
      File kmlFile = new File(gpxFolder.getPath(), pyppeGPSActivity.getCurrentFileName());

      boolean isNewFile = false;
      if (!kmlFile.exists()) {
        kmlFile.createNewFile();
        isNewFile = true;
        startTime = null;
        endTime = null;
        annotatedPlacemarks = "";
      }

      if (isNewFile) {
        BufferedWriter bw = new BufferedWriter(new FileWriter(kmlFile,true));
        String initialXml = START_OF_KML + END_OF_COORDINATES + END_OF_KML;
        bw.write(initialXml);
        bw.flush();
        bw.close();
      }

      long startPosition = kmlFile.length() - END_OF_COORDINATES.getBytes().length - annotatedPlacemarks.getBytes().length - END_OF_KML.getBytes().length;
      String placemark = String.valueOf(loc.getLongitude()) + "," + String.valueOf(loc.getLatitude()) + " " + END_OF_COORDINATES + annotatedPlacemarks + END_OF_KML;

      RandomAccessFile raf = new RandomAccessFile(kmlFile, "rw");
      kmlLock = raf.getChannel().lock();
      raf.seek(startPosition);
      raf.write(placemark.getBytes());
      kmlLock.release();
      raf.close();
      
      final Calendar c = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
      c.setTimeInMillis(loc.getTime());
      if (startTime == null) {
        startTime = c.getTime();
      }
      endTime = c.getTime();
    } catch (IOException e) {
      Log.e("Main", "Could not write file " + e.getMessage());
      pyppeGPSActivity.setStatusText("Could not write to file. " + e.getMessage());
    }

  }

  public void showTagLocationDialog() {
    if (!allowTagging) {
      Utilities.showMessageDialog("Wait", "You can tag a new location, after the coordinates have been updated.", pyppeGPSActivity);
      return;
    }

    AlertDialog.Builder alert = new AlertDialog.Builder(pyppeGPSActivity);
    alert.setTitle("Add a description");
    alert.setMessage("Give a description for your tagged location.");

    // Set an EditText view to get user input
    final EditText input = new EditText(pyppeGPSActivity);
    alert.setView(input);

    alert.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
      public void onClick(DialogInterface dialog, int whichButton) {
        final String desc = Utilities.escapeForXml(input.getText().toString());
        tagLastLocation(desc);
      }

    });
    alert.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
      public void onClick(DialogInterface dialog, int whichButton) {
        // Canceled.
      }
    });

    alert.show();

  }
  
  public void finishCurrentKML() {
    File outputFolder = new File(Environment.getExternalStorageDirectory(), PyppeGPSConstants.OUTPUT_FOLDER);
    File kmlFile = new File(outputFolder.getPath(), pyppeGPSActivity.getCurrentFileName());
    
    if (!kmlFile.exists()) {
      return;
    }
    
    try {
      File tempFile = File.createTempFile("finalKml", ".tmp", outputFolder);
      BufferedWriter bw = new BufferedWriter(new FileWriter(tempFile)); 
      BufferedReader br = new BufferedReader(new FileReader(kmlFile));
      String line = null;
      while ((line = br.readLine()) != null) {
        if (line.contains(EXTRA_DATA)) {
          SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
          // begin must be first, end must be last child
          String extraData = "<TimeSpan>" + "<begin>" + dateFormat.format(startTime) + "</begin>" + "<end>" + dateFormat.format(endTime) + "</end>" + "</TimeSpan>";
          long diffInSeconds = (endTime.getTime() - startTime.getTime()) / 1000;
          extraData +=
            "<ExtendedData>" +
              "<Data name=\""+PyppeGPSConstants.KML_EXTENDED_DATA_DURATION+"\"><value>"+diffInSeconds+"</value></Data>" +
            "</ExtendedData>";
          
          line = line.replace(EXTRA_DATA, extraData);
        }
        bw.write(line);
      }
      br.close();
      bw.close();
      
      kmlFile.delete();
      tempFile.renameTo(kmlFile);
      
    } catch (Exception e) {
      pyppeGPSActivity.setStatusText("Could not insert timestamps to KML-file.");
    }
    
  }

  public void tagLastLocation(String desc) {
    File outputFolder = new File(Environment.getExternalStorageDirectory(), PyppeGPSConstants.OUTPUT_FOLDER);

    if (!outputFolder.exists()) {
      return;
    }

    long startPosition;
    File kmlFile = new File(outputFolder.getPath(), pyppeGPSActivity.getCurrentFileName());

    if (!kmlFile.exists()) {
      return;
    }

    String newAnnotatedPlacemark =
      "<Placemark>" +
      "<name>" + desc + "</name>" +
      "<Point>"+
      "<coordinates>" +
      String.valueOf(pyppeGPSActivity.getCurrentLocation().getLongitude()) + "," + String.valueOf(pyppeGPSActivity.getCurrentLocation().getLatitude()) +
      "</coordinates>" +
      "</Point>" +
      "</Placemark>";
    startPosition = kmlFile.length() - END_OF_KML.getBytes().length;
    try {
      RandomAccessFile raf = new RandomAccessFile(kmlFile, "rw");
      kmlLock = raf.getChannel().lock();
      raf.seek(startPosition);
      String toBeWritten = newAnnotatedPlacemark + END_OF_KML;
      raf.write(toBeWritten.getBytes());
      annotatedPlacemarks += newAnnotatedPlacemark;
      kmlLock.release();
      raf.close();

      allowTagging = false;
    } catch (Exception e) {
      pyppeGPSActivity.setStatusText("Couldn't write description to KML file.");
    }

  }

}
